﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Shell.PocoDot.Configurations
{
    /// <summary>
    /// 默认的 PocoDot 注册处
    /// </summary>
    public class DefaultPocoDotRegistrar : IPocoDotRegistrar
    {
        /// <summary>
        /// 构建一个新的实例
        /// </summary>
        public DefaultPocoDotRegistrar()
        {
            this.Configs = new List<PocoDotConfiguration>();
        }

        /// <summary>
        /// 获取默认的持久层提供器的固定名称
        /// </summary>
        protected virtual string DefaultProviderInvariantName
        {
            get { return "System.Data.SqlClient"; }
        }

        /// <summary>
        /// 获取默认的持久层提供器的令牌清单
        /// </summary>
        protected virtual string DefaultProviderManifestToken
        {
            get { return "2008"; }
        }

        /// <summary>
        /// 获取所有 PocoDot 的配置信息的列表
        /// </summary>
        protected List<PocoDotConfiguration> Configs { get; private set; }

        /// <summary>
        /// 获取所有 PocoDot 的配置信息的集合
        /// </summary>
        public virtual IEnumerable<PocoDotConfiguration> Configurations
        {
            get { return Configs; }
        }

        /// <summary>
        /// 注册一个特定的 PocoDot 的配置信息
        /// </summary>
        /// <param name="configuration">特定的 PocoDot 的配置信息</param>
        /// <exception cref="System.ArgumentNullException">必要参数为空</exception>
        /// <exception cref="System.ArgumentException">重复注册相同类型的 PocoDot 的配置信息</exception>
        public virtual void Register(PocoDotConfiguration configuration)
        {
            lock (this.Configs)
            {
                this.CheckPocoDotConfiguration(configuration);
                this.CheckProviderConfiguration(configuration.Provider);
                Configs.Add(configuration);
            }
        }

        /// <summary>
        /// 检查持久层提供器的配置信息是否合法
        /// </summary>
        /// <param name="pconfig">持久层提供器的配置信息</param>
        /// <remarks>此方法将直接抛出异常, 无需返回结果</remarks>
        protected virtual void CheckProviderConfiguration(ProviderConfiguration pconfig)
        {
            ConfigurationHelper.Check(pconfig,
                this.DefaultProviderInvariantName, this.DefaultProviderManifestToken);
        }

        /// <summary>
        /// 检查 PocoDot 的配置信息是否合法
        /// </summary>
        /// <param name="dconfig">PocoDot 的配置信息</param>
        /// <remarks>此方法将直接抛出异常, 无需返回结果</remarks>
        protected virtual void CheckPocoDotConfiguration(PocoDotConfiguration dconfig)
        {
            if (dconfig == null)
            {
                throw new ArgumentNullException("config");
            }
            if (dconfig.PocoDot == null)
            {
                throw new ArgumentNullException("config.PocoDot");
            }
            if (dconfig.Provider == null)
            {
                throw new ArgumentNullException("config.Provider");
            }
            if (this.Configs.Any(c => c.PocoDot == dconfig.PocoDot))
            {
                throw new ArgumentException(SR.Get("Error.DuplicatedPocoDotConfigurationFound", dconfig.PocoDot.Name));
            }
        }
    }
}
